import { ref, inject, nextTick, onMounted, computed } from "vue";
import { uniqueId, cloneDeep, lastIndexOf, merge } from "lodash-es";
import Vuex from "vuex";
import { listIcons } from "@iconify/vue2";

import { startProcess } from "@/api/activiti/monitor.js";

import store from "@/store/index.js";

/**
 * @description
 * 最核心的业务信息结构 此处会负责定义工作流全部需要存储的字段。这里仅仅是定义一个vuex实例的module.store属性值
 *
 * 只负责定义和声明。最多提供一些初始化。此外不会做额外的行为。
 *
 * 事实上是本文件的唯一单例。
 *
 * 设计理由：
 * 用于工作流详情组件统一实现数据管理。特别是兄弟组件之间的数据传值。
 *
 * 对外导出 仅用于类型声明
 */
export const activitiInfoStore = {
  /** 实例id 流程实例id */
  instanceId: "",

  /** 业务id 各个业务提供的主键id */
  businessKey: "",

  /** 任务id */
  taskId: "",

  /** 业务单据 */
  module: "",

  /** 当前处理人id */
  currentUserIds: "",

  /** 该节点当前的用户信息
   * @type { [] }
   */
  nodeCurrentUser: [],

  /** 组件状态 仅用于声明工作流组件本身的一些状态 默认为新增模式
   * @type { import("../types/activitiInfo.ts").ComponentsStatus  }
   */
  componentsStatus: "add",

  /** 任务信息
   * @type { import("@/types/TaskInfoVO").TaskInfoVO | {} }
   */
  taskInfo: {},

  /** 当前节点的全部审批人数组
   * @type { import("@/types/TaskActorVO").TaskActorVO[] }
   */
  taskActorVOList: [],

  /** 流程实例信息
   * @type { import("@/types/InstanceBusiness").InstanceBusiness }
   */
  instanceInfo: {},
};

/** 干净 完全清空的数据实例 用于实现数据重设 */
const clearFieldActivitiInfoStore = cloneDeep(activitiInfoStore);

/** 创建一个新的 工作流信息存储模块
 * @description
 * 目的是为了创建一个动态加载删减的模块。
 *
 * @deprecated
 * 不考虑动态模块管理了。
 */
export function createActivitiInfoModule() {
  /**
   * @type { import("vuex").Module< typeof activitiInfoStore > }
   * @description
   * 一个全局store的模块。
   */
  const activitiInfoModule = {
    state: cloneDeep(activitiInfoStore),
  };

  return activitiInfoModule;
}

/** 使用 工作流信息 */
export function useActivitiInfo() {
  // @type { import("vue").Ref< typeof activitiInfoStore >  }
  /**
   * 本地存储的信息 目前被设计为全局单例
   */
  const localStoreInfo = ref(activitiInfoStore);

  /** 自动运算的 工作流数据实例
   * @description
   * 仅仅是一个只读数据 用computed实现js内的只读
   */
  const activitiInfoComputed = computed(() => localStoreInfo.value);

  /** 清空工作流数据 清空全部的字段 至初始化形式 */
  function clearActivitiInfo() {
    localStoreInfo.value = merge(
      localStoreInfo.value,
      clearFieldActivitiInfoStore
    );
  }

  /**
   * 实例id
   * @description
   * 从store存储内统一获得的值
   * @type { string | undefined }
   */
  const instanceId = localStoreInfo.value.instanceId;

  /** 是否启动工作流？
   * @description
   * 只要存在实例id，就是启动了工作流。
   * 存在实例id -> 已启动
   * 没有实例id -> 未启动
   *
   * 设计理由
   * 主要用于其他组件识别出是否要显示出启动按钮。
   */
  const hasStartActiviti = computed(() => !!localStoreInfo.value.instanceId);

  /** 是否可以发起工作流审批？
   * @description
   * 已经存在业务id的，但是没有实例id的 情况下。就说明允许发起工作流审批。
   * @deprecated 目前该写法 被一个watch函数实现了 算法相同
   * 未来可能会考虑将watch整合进来
   *
   * TODO:
   * 检查一下，多组件内共用组合式api，其watch是否会出现反复执行？其挖watch监听的单例，是否出现了性能问题？
   */
  const canStartActiviti = computed(
    () => !!localStoreInfo.value.businessKey && !localStoreInfo.value.instanceId
  );

  /** 当前用户是否有待办任务？ */
  const isCurrentUserHasTodoTask = computed(
    () => !!localStoreInfo.value.taskActorVOList.length
  );

  /** 当前用户id
   * @description
   * 默认从当前框架的store内获取值
   * @type { import("vue").ComputedRef< string > } 获取字符串格式的用户id
   */
  const currentUserId = computed(() => {
    /**
     * @description
     * 用户信息
     *
     * 有疑惑 无法在后端内 找到用户登录成功后的接口 并找到返回值的实体 故无法生成类型声明文件
     * auth/user
     * @type { Record<string, unknown> }
     */
    const user = store.state.account.user;
    return user.userId;
  });

  /** 当前的任务 是否是当前用户的？
   * @description
   * 在获得任务信息的前提下 判断当前账户的用户信息是否相同
   */
  const isCurrentUserTask = computed(() => {
    return localStoreInfo.value.taskInfo?.userId === currentUserId.value;
  });

  /** 是否可以显示右侧 侧边栏？
   * @description
   * 用工作流接口数据，来告诉侧边栏是否可以显示。
   * 相当于严格的权限管理。
   * 本变量仅仅负责告诉其他组件，侧边栏有没有权限显示出来。
   *
   * true 可以显示
   * fasle 不允许显示
   */
  const canShowAside = computed(() => {
    // 如果当前有任务，并且是这个用户的待办任务，就可以显示侧边栏。允许显示。
    return isCurrentUserTask.value;
    // 警告: 临时数据测试 默认总是可以显示
    // return true;
  });

  /**
   * 任务标题
   * @type { import("vue").ComputedRef< string | undefined > }
   */
  const taskInfoTitle = computed(
    // 有疑惑 遇到bug 无法使用有效的可选链操作符
    // () => localStoreInfo.value.taskInfo?.title ?? "未显示值的默认标题"
    // 这里故意移除 等以后再处理此问题
    () => "未显示值的默认标题"
  );

  function setModeToAdd() {
    localStoreInfo.value.componentsStatus = "add";
  }
  function setModeToUnstart() {
    localStoreInfo.value.componentsStatus = "unstart";
  }

  /** 工作流组件 当前是否是新增模式？
   * @description
   * 设计理由
   * 让工作流组件去对外告诉其他的组件，本组件是新增模式。
   */
  const isAdd = computed(() => localStoreInfo.value.componentsStatus === "add");

  /** 是否是未启动模式？ */
  const isUnstart = computed(
    () => localStoreInfo.value.componentsStatus === "unstart"
  );

  /** 启动工作流 事实上可以作为单纯的工具函数 交给用户使用
   * @param { import("@/types/StartExtendArgsDTO").StartExtendArgsDTO } params 流程启动接口的参数
   */
  async function startActivitiProcess(params) {
    await startProcess(params)
      .then((res) => {
        console.log(" in startProcess ", res);
      })
      .catch()
      .finally();
  }

  return {
    activitiInfo: localStoreInfo,
    activitiInfoComputed,
    isAdd,
    isUnstart,
    isCurrentUserHasTodoTask,
    isCurrentUserTask,
    canShowAside,
    instanceId,
    taskInfoTitle,
    hasStartActiviti,
    canStartActiviti,

    startActivitiProcess,
    clearActivitiInfo,
    setModeToAdd,
    setModeToUnstart,
  };
}
